<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
<meta http-equiv="X-UA-Compatible" content="IE=9"/>
<meta name="generator" content="Doxygen 1.8.6"/>
<title>LiquidFun Programmer&#39;s Guide: Collision Module</title>
<link href="tabs.css" rel="stylesheet" type="text/css"/>
<script type="text/javascript" src="jquery.js"></script>
<script type="text/javascript" src="dynsections.js"></script>
<link href="navtree.css" rel="stylesheet" type="text/css"/>
<script type="text/javascript" src="resize.js"></script>
<script type="text/javascript" src="navtree.js"></script>
<script type="text/javascript">
  $(document).ready(initResizable);
  $(window).load(resizeHeight);
</script>
<link href="doxygen.css" rel="stylesheet" type="text/css" />
</head>
<body>
<div id="top"><!-- do not remove this div, it is closed by doxygen! -->
<div id="titlearea">
<table cellspacing="0" cellpadding="0">
 <tbody>
 <tr style="height: 56px;">
  <td style="padding-left: 0.5em;">
   <div id="projectname">LiquidFun Programmer&#39;s Guide
   </div>
  </td>
 </tr>
 </tbody>
</table>
</div>
<!-- end header part -->
<!-- Generated by Doxygen 1.8.6 -->
</div><!-- top -->
<div id="side-nav" class="ui-resizable side-nav-resizable">
  <div id="nav-tree">
    <div id="nav-tree-contents">
      <div id="nav-sync" class="sync"></div>
    </div>
  </div>
  <div id="splitbar" style="-moz-user-select:none;" 
       class="ui-resizable-handle">
  </div>
</div>
<script type="text/javascript">
$(document).ready(function(){initNavTree('md__chapter04__collision__module.html','');});
</script>
<div id="doc-content">
<div class="header">
  <div class="headertitle">
<div class="title">Collision Module </div>  </div>
</div><!--header-->
<div class="contents">
<div class="textblock"><p><a href="#about">About</a><br/>
 <a href="#shapes">Shapes</a><br/>
 <a href="#un">Unary Geometric Queries</a><br/>
 <a href="#bf">Binary Functions</a><br/>
 <a href="#dt">Dynamic Tree</a><br/>
 <a href="#bp">Broad-Phase</a><br/>
</p>
<p><a class="anchor" id="about"></a> </p>
<h2>About</h2>
<p>The Collision module contains shapes and functions that operate on them. The module also contains a dynamic tree and broad-phase to acceleration collision processing of large systems.</p>
<p>The collision module is designed to be usable outside of the dynamic system. For example, you can use the dynamic tree for other aspects of your game besides physics.</p>
<p>However, the main purpose of LiquidFun is to provide a rigid body physics engine, so the using the collision module by itself may feel limited for some applications. Likewise, I will not make a strong effort to document it or polish the APIs.</p>
<p><a class="anchor" id="shapes"></a> </p>
<h2>Shapes</h2>
<p>Shapes describe collision geometry and may be used independently of physics simulation. At a minimum, you should understand how to create shapes that can be later attached to rigid bodies.</p>
<p>LiquidFun shapes implement the b2Shape base class. The base class defines functions to:</p>
<ul>
<li>Test a point for overlap with the shape.</li>
<li>Perform a ray cast against the shape.</li>
<li>Compute the shape's AABB.</li>
<li>Compute the mass properties of the shape.</li>
</ul>
<p>In addition, each shape has a type member and a radius. The radius even applies to polygons, as discussed below.</p>
<p>Keep in mind that a shape does not know about bodies and stand apart from the dynamics system. Shapes are stored in a compact form that is optimized for size and performance. As such, shapes are not easily moved around. You have to manually set the shape vertex positions to move a shape. However, when a shape is attached to a body using a fixture, the shapes move rigidly with the host body. In summary:</p>
<ul>
<li>When a shape is <b>not</b> attached to a body, you can view it’s vertices as being expressed in world-space.</li>
<li>When a shape is attached to a body, you can view it’s vertices as being expressed in local coordinates.</li>
</ul>
<h3>Circle Shapes</h3>
<p>Circle shapes have a position and radius. Circles are solid. You cannot make a hollow circle using the circle shape.</p>
<p>&#160;&#160;&#160;<code>b2CircleShape circle;</code><br/>
 &#160;&#160;&#160;<code>circle.m_p.Set(2.0f, 3.0f);</code><br/>
 &#160;&#160;&#160;<code>circle.m_radius = 0.5f;</code><br/>
</p>
<h3>Polygon Shapes</h3>
<p>Polygon shapes are solid convex polygons. A polygon is convex when all line segments connecting two points in the interior do not cross any edge of the polygon. Polygons are solid and never hollow. A polygon must have 3 or more vertices.</p>
<div class="image">
<img src="image_3.gif"  align="center" alt="Polygon shapes" height="125" width="223"/>
</div>
<p><br/>
</p>
<p>Polygon vertices are stored with a counter clockwise winding (CCW). We must be careful because the notion of CCW is with respect to a right-handed coordinate system with the z-axis pointing out of the plane. This might turn out to be clockwise on your screen, depending on your coordinate system conventions.</p>
<div class="image">
<img src="image_4.png"  align="center" alt="Polygon vertices" height="176" width="347"/>
</div>
<p><br/>
</p>
<p>The polygon members are public, but you should use initialization functions to create a polygon. The initialization functions create normal vectors and perform validation.</p>
<p>You can create a polygon shape by passing in a vertex array. The maximal size of the array is controlled by b2_maxPolygonVertices which has a default value of 8. This is sufficient to describe most convex polygons.</p>
<p>The b2PolygonShape::Set function automatically computes the convex hull and establishes the proper winding order. This function is fast when the number of vertices is low. If you increase b2_maxPolygonVertices, then the convex hull computation might become slow. Also note that the convex hull function may eliminate and/or re-order the points you provide.</p>
<p>&#160;&#160;&#160;<code>// This defines a triangle in CCW order.</code><br/>
 &#160;&#160;&#160;<code>b2Vec2 vertices[3];</code><br/>
 &#160;&#160;&#160;<code>vertices[0].Set(0.0f, 0.0f);</code><br/>
 &#160;&#160;&#160;<code>vertices[1].Set(1.0f, 0.0f);</code><br/>
 &#160;&#160;&#160;<code>vertices[2].Set(0.0f, 1.0f);</code><br/>
 &#160;&#160;&#160;<code>int32 count = 3;</code><br/>
 &#160;&#160;&#160;<code>b2PolygonShape polygon;</code><br/>
 &#160;&#160;&#160;<code>polygon.Set(vertices, count);</code><br/>
</p>
<p>The polygon shape has some convenience functions to create boxes.</p>
<p>&#160;&#160;&#160;<code>void SetAsBox(float32 hx, float32 hy);</code><br/>
 &#160;&#160;&#160;<code>void SetAsBox(float32 hx, float32 hy, const b2Vec2&amp; center, float32 angle);</code><br/>
</p>
<p>Polygons inherit a radius from b2Shape. The radius creates a skin around the polygon. The skin is used in stacking scenarios to keep polygons slightly separated. This allows continuous collision to work against the core polygon.</p>
<div class="image">
<img src="image_5.png"  align="center" alt="Polygon skin" height="270" width="300"/>
</div>
<p><br/>
 The polygon skin helps prevent tunneling by keeping the polygons separated. This results in small gaps between the shapes. Your visual representation can be larger than the polygon to hide any gaps.</p>
<div class="image">
<img src="image_6.png"  align="center" alt="Polygons collide" height="109" width="322"/>
</div>
<p><br/>
</p>
<h3>Edge Shapes</h3>
<p>Edge shapes are line segments. These are provided to assist in making a free-form static environment for your game. A major limitation of edge shapes is that they can collide with circles and polygons but not with themselves. The collision algorithms used by LiquidFun require that at least one of two colliding shapes have volume. Edge shapes have no volume, so edge-edge collision is not possible.</p>
<p>&#160;&#160;&#160;<code>// This an edge shape.</code><br/>
 &#160;&#160;&#160;<code>b2Vec2 v1(0.0f, 0.0f);</code><br/>
 &#160;&#160;&#160;<code>b2Vec2 v2(1.0f, 0.0f);</code><br/>
 &#160;&#160;&#160;<code>b2EdgeShape edge;</code><br/>
 &#160;&#160;&#160;<code>edge.Set(v1, v2);</code><br/>
</p>
<p>In many cases a game environment is constructed by connecting several edge shapes end-to-end. This can give rise to an unexpected artifact when a polygon slides along the chain of edges. In the figure below we see a box colliding with an internal vertex. These <em>ghost</em> collisions are caused when the polygon collides with an internal vertex generating an internal collision normal.</p>
<div class="image">
<img src="image_7.png"  align="center" alt="Ghost collision" height="154" width="315"/>
</div>
<p><br/>
 If edge1 did not exist this collision would seem fine. With edge1 present, the internal collision seems like a bug. But normally when LiquidFun collides two shapes, it views them in isolation.</p>
<p>Fortunately, the edge shape provides a mechanism for eliminating ghost collisions by storing the adjacent *ghost *vertices. LiquidFun uses these ghost vertices to prevent internal collisions.</p>
<div class="image">
<img src="image_8.png"  align="center" alt="Ghost vertices" height="153" width="332"/>
</div>
<p><br/>
 &#160;&#160;&#160;<code>// This is an edge shape with ghost vertices.</code><br/>
 &#160;&#160;&#160;<code>b2Vec2 v0(1.7f, 0.0f);</code><br/>
 &#160;&#160;&#160;<code>b2Vec2 v1(1.0f, 0.25f);</code><br/>
 &#160;&#160;&#160;<code>b2Vec2 v2(0.0f, 0.0f);</code><br/>
 &#160;&#160;&#160;<code>b2Vec2 v3(-1.7f, 0.4f);</code><br/>
 &#160;&#160;&#160;<code>b2EdgeShape edge;</code><br/>
 &#160;&#160;&#160;<code>edge.Set(v1, v2);</code><br/>
 &#160;&#160;&#160;<code>edge.m_hasVertex0 = true;</code><br/>
 &#160;&#160;&#160;<code>edge.m_hasVertex3 = true;</code><br/>
 &#160;&#160;&#160;<code>edge.m_vertex0 = v0;</code><br/>
 &#160;&#160;&#160;<code>edge.m_vertex3 = v3;</code><br/>
</p>
<p>In general stitching edges together this way is a bit wasteful and tedious. This brings us to chain shapes.</p>
<h3>Chain Shapes</h3>
<p>The chain shape provides an efficient way to connect many edges together to construct your static game worlds. Chain shapes automatically eliminate ghost collisions and provide two-sided collision.</p>
<div class="image">
<img src="image_9.png"  align="center" alt="Chain shape" height="165" width="305"/>
</div>
<p><br/>
 &#160;&#160;&#160;<code>// This a chain shape with isolated vertices</code><br/>
 &#160;&#160;&#160;<code>b2Vec2 vs[4];</code><br/>
 &#160;&#160;&#160;<code>vs[0].Set(1.7f, 0.0f);</code><br/>
 &#160;&#160;&#160;<code>vs[1].Set(1.0f, 0.25f);</code><br/>
 &#160;&#160;&#160;<code>vs[2].Set(0.0f, 0.0f);</code><br/>
 &#160;&#160;&#160;<code>vs[3].Set(-1.7f, 0.4f);</code><br/>
 &#160;&#160;&#160;<code>b2ChainShape chain;</code><br/>
 &#160;&#160;&#160;<code>chain.CreateChain(vs, 4);</code><br/>
</p>
<p>You may have a scrolling game world and would like to connect several chains together. You can connect chains together using ghost vertices, like we did with b2EdgeShape.</p>
<p>&#160;&#160;&#160;<code>// Install ghost vertices</code><br/>
 &#160;&#160;&#160;<code>chain.SetPrevVertex(b2Vec2(3.0f, 1.0f));</code><br/>
 &#160;&#160;&#160;<code>chain.SetNextVertex(b2Vec2(-2.0f, 0.0f));</code><br/>
</p>
<p>You may also create loops automatically.</p>
<p>&#160;&#160;&#160;<code>// Create a loop. The first and last vertices are connected.</code><br/>
 &#160;&#160;&#160;<code>b2ChainShape chain;</code><br/>
 &#160;&#160;&#160;<code>chain.CreateLoop(vs, 4);</code><br/>
</p>
<p>Self-intersection of chain shapes is not supported. It might work, it might not. The code that prevents ghost collisions assumes there are no self-intersections of the chain. Also, very close vertices can cause problems. Make sure all your edges are longer than b2_linearSlop (5mm).</p>
<div class="image">
<img src="image_10.png"  align="center" alt="No self-intersection" height="178" width="335"/>
</div>
<p><br/>
 Each edge in the chain is treated as a child shape and can be accessed by index. When a chain shape is connected to a body, each edge gets its own bounding box in the broad-phase collision tree.</p>
<p>&#160;&#160;&#160;<code>// Visit each child edge.</code><br/>
 &#160;&#160;&#160;<code>for (int32 i = 0; i &lt; chain.GetChildCount(); ++i)</code><br/>
 &#160;&#160;&#160;<code>{</code><br/>
 &#160;&#160;&#160;&#160;&#160;&#160;<code>b2EdgeShape edge;</code><br/>
 &#160;&#160;&#160;&#160;&#160;&#160;<code>chain.GetChildEdge(&amp;edge, i);</code><br/>
 &#160;&#160;&#160;&#160;&#160;&#160;<code>…</code><br/>
 &#160;&#160;&#160;<code>}</code><br/>
</p>
<p><a class="anchor" id="un"></a> </p>
<h2>Unary Geometric Queries</h2>
<p>You can perform a couple of geometric queries on a single shape.</p>
<h3>Shape Point Test</h3>
<p>You can test a point for overlap with a shape. You provide a transform for the shape and a world point.</p>
<p>&#160;&#160;&#160;<code>b2Transfrom transform;</code><br/>
 &#160;&#160;&#160;<code>transform.SetIdentity();</code><br/>
 &#160;&#160;&#160;<code>b2Vec2 point(5.0f, 2.0f);</code><br/>
 &#160;&#160;&#160;<code>bool hit = shape-&gt;TestPoint(transform, point);</code><br/>
</p>
<p>Edge and chain shapes always return false, even if the chain is a loop.</p>
<h3>Shape Ray Cast</h3>
<p>You can cast a ray at a shape to get the point of first intersection and normal vector. No hit will register if the ray starts inside the shape. A child index is included for chain shapes because the ray cast will only check a single edge at a time.</p>
<p>&#160;&#160;&#160;<code>b2Transfrom transform;</code><br/>
 &#160;&#160;&#160;<code>transform.SetIdentity();</code><br/>
 &#160;&#160;&#160;<code>b2RayCastInput input;</code><br/>
 &#160;&#160;&#160;<code>input.p1.Set(0.0f, 0.0f, 0.0f);</code><br/>
 &#160;&#160;&#160;<code>input.p2.Set(1.0f, 0.0f, 0.0f);</code><br/>
 &#160;&#160;&#160;<code>input.maxFraction = 1.0f;</code><br/>
 &#160;&#160;&#160;<code>int32 childIndex = 0;</code><br/>
 &#160;&#160;&#160;<code>b2RayCastOutput output;</code><br/>
 &#160;&#160;&#160;<code>bool hit = shape-&gt;RayCast(&amp;output, input, transform, childIndex);</code><br/>
 &#160;&#160;&#160;<code>if (hit)</code><br/>
 &#160;&#160;&#160;<code>{</code><br/>
 &#160;&#160;&#160;&#160;&#160;&#160;<code>b2Vec2 hitPoint = input.p1 + output.fraction * (input.p2 – input.p1);</code><br/>
 &#160;&#160;&#160;&#160;&#160;&#160;<code>…</code><br/>
 &#160;&#160;&#160;<code>}</code><br/>
</p>
<p><a class="anchor" id="bf"></a> </p>
<h2>Binary Functions</h2>
<p>The Collision module contains bilateral functions that take a pair of shapes and compute some results. These include:</p>
<ul>
<li>Overlap</li>
<li>Contact manifolds</li>
<li>Distance</li>
<li>Time of impact</li>
</ul>
<h3>Overlap</h3>
<p>You can test two shapes for overlap using this function:</p>
<p>&#160;&#160;&#160;<code>b2Transform xfA = …, xfB = …;</code><br/>
 &#160;&#160;&#160;<code>bool overlap = b2TestOverlap(shapeA, indexA, shapeB, indexB, xfA, xfB);</code><br/>
</p>
<p>Again you must provide child indices to for the case of chain shapes.</p>
<h3>Contact Manifolds</h3>
<p>LiquidFun has functions to compute contact points for overlapping shapes. If we consider circle-circle or circle-polygon, we can only get one contact point and normal. In the case of polygon-polygon we can get two points. These points share the same normal vector so LiquidFun groups them into a manifold structure. The contact solver takes advantage of this to improve stacking stability.</p>
<div class="image">
<img src="image_11.png"  align="center" alt="Manifold structure" height="300" width="419"/>
</div>
<p><br/>
 Normally you don’t need to compute contact manifolds directly, however you will likely use the results produced in the simulation.</p>
<p>The b2Manifold structure holds a normal vector and up to two contact points. The normal and points are held in local coordinates. As a convenience for the contact solver, each point stores the normal and tangential (friction) impulses.</p>
<p>The data stored in b2Manifold is optimized for internal use. If you need this data, it is usually best to use the b2WorldManifold structure to generate the world coordinates of the contact normal and points. You need to provide a b2Manifold and the shape transforms and radii.</p>
<p>&#160;&#160;&#160;<code>b2WorldManifold worldManifold;</code><br/>
 &#160;&#160;&#160;<code>worldManifold.Initialize(&amp;manifold, transformA, shapeA.m_radius, transformB, shapeB.m_radius);</code><br/>
 &#160;&#160;&#160;<code>for (int32 i = 0; i &lt; manifold.pointCount; ++i)</code><br/>
 &#160;&#160;&#160;<code>{</code><br/>
 &#160;&#160;&#160;&#160;&#160;&#160;<code>b2Vec2 point = worldManifold.points[i];</code><br/>
 &#160;&#160;&#160;&#160;&#160;&#160;<code>…</code><br/>
 &#160;&#160;&#160;<code>}</code><br/>
</p>
<p>Notice that the world manifold uses the point count from the original manifold.</p>
<p>During simulation shapes may move and the manifolds may change. Points may be added or removed. You can detect this using b2GetPointStates.</p>
<p>&#160;&#160;&#160;<code>b2PointState state1[2], state2[2];</code><br/>
 &#160;&#160;&#160;<code>b2GetPointStates(state1, state2, &amp;manifold1, &amp;manifold2);</code><br/>
 &#160;&#160;&#160;<code>if (state1[0] == b2_removeState)</code><br/>
 &#160;&#160;&#160;<code>{</code><br/>
 &#160;&#160;&#160;&#160;&#160;&#160;<code>// process event</code><br/>
 &#160;&#160;&#160;<code>}</code><br/>
</p>
<h3>Distance</h3>
<p>The b2Distance function can be used to compute the distance between two shapes. The distance function needs both shapes to be converted into a b2DistanceProxy. There is also some caching used to warm start the distance function for repeated calls. You can see the details in b2Distance.h.</p>
<div class="image">
<img src="image_12.png"  align="center" alt="Distance" height="134" width="271"/>
</div>
<p><br/>
 </p>
<h3>Time of Impact</h3>
<p>If two shapes are moving fast, they may <em>tunnel</em> through each other in a single time step.</p>
<div class="image">
<img src="image_13.png"  align="center" alt="Time-of-impact tunneling" height="133" width="234"/>
</div>
<p><br/>
 The b2TimeOfImpact function is used to determine the time when two moving shapes collide. This is called the *time of impact *(TOI). The main purpose of b2TimeOfImpact is for tunnel prevention. In particular, it is designed to prevent moving objects from tunneling outside of static level geometry.</p>
<p>This function accounts for rotation and translation of both shapes, however if the rotations are large enough, then the function may miss a collision. However the function will still report a non-overlapped time and will capture all translational collisions.</p>
<p>The time of impact function identities an initial separating axis and ensures the shapes do not cross on that axis. This might miss collisions that are clear at the final positions. While this approach may miss some collisions, it is very fast and adequate for tunnel prevention.</p>
<div class="image">
<img src="image_14.png"  align="center" alt="Captured collision" height="169" width="297"/>
</div>
<p><br/>
 </p>
<div class="image">
<img src="image_15.png"  align="center" alt="Missed collision" height="172" width="297"/>
</div>
<p><br/>
 It is difficult to put a restriction on the rotation magnitude. There may be cases where collisions are missed for small rotations. Normally, these missed rotational collisions should not harm game play. They tend to be glancing collisions.</p>
<p>The function requires two shapes (converted to b2DistanceProxy) and two b2Sweep structures. The sweep structure defines the initial and final transforms of the shapes.</p>
<p>You can use fixed rotations to perform a <em>shape cast</em>. In this case, the time of impact function will not miss any collisions.</p>
<p><a class="anchor" id="dt"></a> </p>
<h2>Dynamic Tree</h2>
<p>The b2DynamicTree class is used by LiquidFun to organize large numbers of shapes efficiently. The class does not know about shapes. Instead it operates on axis-aligned bounding boxes (AABBs) with user data pointers.</p>
<p>The dynamic tree is a hierarchical AABB tree. Each internal node in the tree has two children. A leaf node is a single user AABB. The tree uses rotations to keep the tree balanced, even in the case of degenerate input.</p>
<p>The tree structure allows for efficient ray casts and region queries. For example, you may have hundreds of shapes in your scene. You could perform a ray cast against the scene in a brute force manner by ray casting each shape. This would be inefficient because it does not take advantage of shapes being spread out. Instead, you can maintain a dynamic tree and perform ray casts against the tree. This traverses the ray through the tree skipping large numbers of shapes.</p>
<p>A region query uses the tree to find all leaf AABBs that overlap a query AABB. This is faster than a brute force approach because many shapes can be skipped.</p>
<div class="image">
<img src="image_16.png"  align="center" alt="Ray cast" height="249" width="248"/>
</div>
<p><br/>
 </p>
<div class="image">
<img src="image_17.png"  align="center" alt="Region query" height="210" width="231"/>
</div>
<p><br/>
 Normally you will not use the dynamic tree directly. Rather you will go through the b2World class for ray casts and region queries. If you plan to instantiate your own dynamic tree, you can learn how to use it by looking at how LiquidFun uses it.</p>
<p><a class="anchor" id="bp"></a> </p>
<h2>Broad-phase</h2>
<p>Collision processing in a physics step can be divided into narrow-phase and broad-phase. In the narrow-phase we compute contact points between pairs of shapes. Imagine we have N shapes. Using brute force, we would need to perform the narrow-phase for N*N/2 pairs.</p>
<p>The b2BroadPhase class reduces this load by using a dynamic tree for pair management. This greatly reduces the number of narrow-phase calls.</p>
<p>Normally you do not interact with the broad-phase directly. Instead, LiquidFun creates and manages a broad-phase internally. Also, b2BroadPhase is designed with LiquidFun’s simulation loop in mind, so it is likely not suited for other use cases.</p>
<p><em>This content is licensed under <a href="http://creativecommons.org/licenses/by/4.0/legalcode">Creative Commons Attribution 4.0</a>. For details and restrictions, please see the <a href="md__content_license.html">Content License</a>.</em> </p>
</div></div><!-- contents -->
</div><!-- doc-content -->
<!-- Google Analytics -->
<script>
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
})(window,document,'script','//www.google-analytics.com/analytics.js','ga');
ga('create', 'UA-46159502-1', 'auto');
ga('create', 'UA-49880327-7', 'auto', {'name': 'liquidFunTracker'});
ga('send', 'pageview');
ga('liquidFunTracker.send', 'pageview');
</script>
</body>
</html>
